/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.fd.service.impl;

import com.xy.biz.fd.client.DocumentClient;
import com.xy.biz.fd.domain.bo.*;
import com.xy.biz.fd.domain.consts.DocumentRubbishConstant;
import com.xy.biz.fd.domain.converter.FileExtensionConverter;
import com.xy.biz.fd.domain.converter.FolderConverter;
import com.xy.biz.fd.domain.query.DocumentFavoriteQuery;
import com.xy.biz.fd.domain.query.DocumentQuery;
import com.xy.biz.fd.domain.query.DocumentRubbishQuery;
import com.xy.biz.fd.domain.query.FolderQuery;
import com.xy.biz.fd.domain.req.document.CopyDocumentRequest;
import com.xy.biz.fd.domain.req.folder.CreateManufactureFolderRequest;
import com.xy.biz.fd.domain.req.folder.ListFolderRequest;
import com.xy.biz.fd.domain.resp.GetFileExtensionResponse;
import com.xy.biz.fd.domain.resp.GetFolderResponse;
import com.xy.biz.fd.manager.*;
import com.xy.biz.fd.manager.impl.FolderManagerImpl;
import com.xy.biz.fd.service.FolderService;
import com.xy.biz.uc.client.UserClient;
import com.xy.lang.domain.Result;
import com.xy.lang.domain.treeing.Tree;
import com.xy.lang.domain.treeing.TreeItem;
import com.xy.lang.util.CalendarUtils;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.util.ConvertSizeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 *
 * @author ssl
 * @date 2021-1-23
 */
@Service
public class FolderServiceImpl implements FolderService, InitializingBean {

    @Autowired
    private FolderManager folderManager;

    @Autowired
    private DocumentRubbishManager documentRubbishManager;

    @Autowired
    private DocumentManager documentManager;

    @Autowired
    private DocumentEventBus documentEventBus;

    @Autowired
    private DocumentFavoriteManager documentFavoriteManager;

    @Autowired
    private UserClient userClient;

    @Autowired
    private DocumentClient documentClient;

    @Autowired
    private RepositoryManager repositoryManager;

    @Override
    public Result<GetFolderResponse> saveFolder(FolderBO folderBO) {
        buildFolderBo(folderBO);
        folderBO = folderManager.saveFolder(folderBO);
        if (Objects.nonNull(folderBO)) {
            return Result.success(FolderConverter.toResponse(folderBO));
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> saveAllFolder(Collection<FolderBO> collection) {
        collection.stream().forEach(item -> {
            buildFolderBo(item);
        });
        int affectedRows = folderManager.saveAllFolder(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    private void buildFolderBo(FolderBO folderBO) {
        if (folderBO.getParentFolderId() == null) {
            folderBO.setParentFolderId(0L);
        }
        //添加文件路径
        RepositoryBO repository = repositoryManager.getRepository(folderBO.getRepositoryId());
        if (repository != null) {
            StringBuffer sb = new StringBuffer(repository.getRepositoryName() + "://");
            getFolderName(folderBO.getParentFolderId(), sb);
            folderBO.setLocation(sb.toString());
        }
        folderBO.setTenantId(UserContextHolder.getTenantId());
        folderBO.setCreateUserId(UserContextHolder.getUserId());
        LocalDateTime now = LocalDateTime.now();
        folderBO.setAccessTime(now);
        folderBO.setCreateTime(now);
        folderBO.setUpdateTime(now);
        folderBO.setDeleteFlag(Boolean.FALSE);
    }

    @Override
    public Result<?> updateFolder(FolderBO folderBO) {
        LocalDateTime now = LocalDateTime.now();
        folderBO.setUpdateTime(now);
        folderBO.setAccessTime(now);
        int affectedRows = folderManager.updateFolder(folderBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Transactional
    @Override
    public Result<?> deleteFolder(Long folderId) {
        FolderBO folder = folderManager.getFolder(folderId);
        if (null == folder) {
            return Result.ofNotFound("文件夹不存在", folderId);
        }
        RepositoryBO repositoryBO = documentEventBus.getRubbishRepository();
        if (repositoryBO == null) {
            return Result.ofErrorStatus("回收站初始化失败");
        }
        //源数据
        FolderBO srcFolder = new FolderBO();
        BeanUtils.copyProperties(folder, srcFolder);
        //回收的垃圾文件夹
        DocumentRubbishBO documentRubbishBO = new DocumentRubbishBO();
        LocalDateTime now = LocalDateTime.now();
        documentRubbishBO.setCreateTime(now);
        documentRubbishBO.setUpdateTime(now);
        documentRubbishBO.setTenantId(UserContextHolder.getUserId());
        documentRubbishBO.setRubbishType(DocumentRubbishConstant.GARBAGE_TYPE_FOLDER);    //文件类型
        documentRubbishBO.setRubbishRepositoryId(repositoryBO.getRepositoryId());    //回收知识库id
        documentRubbishBO.setSourceRepositoryId(folder.getRepositoryId());//源知识库id
        documentRubbishBO.setSourceFolderId(folder.getParentFolderId());//源文件id
        documentRubbishBO.setRubbishId(folder.getFolderId());    //垃圾id
        int rows = documentRubbishManager.saveDocumentRubbish(documentRubbishBO);
        if (rows > 0) {
            // 添加成功
            folder.setRepositoryId(repositoryBO.getRepositoryId());
            folder.setParentFolderId(0L);
            folder.setUpdateTime(LocalDateTime.now());
            rows = folderManager.updateFolder(folder);
            if (rows > 0) {
                //此方法只用于计算文件夹删除时的文件大小
                documentEventBus.fireFolderDelHandler(folderId);
                documentEventBus.fireFoldertMoveHandler(srcFolder);
                //删除文件夹的分享
                documentEventBus.fireFolderStatusHandler(srcFolder.getFolderId());
                return Result.success();
            }
        }
//		int affectedRows = folderManager.deleteFolder(folderId);
//		if (affectedRows > 0) {
//			return Result.success();
//		}
        return Result.ofErrorRowsAffected();
    }

    /**
     * 批量删除文件夹
     *
     * @param folderIds
     */
    @Transactional
    @Override
    public Result<?> deleteFolderByIds(Collection<Long> folderIds) {
        List<FolderBO> folderBOS = folderManager.listFolderById(folderIds);
        if (null == folderBOS || CollectionUtils.isEmpty(folderBOS)) {
            return Result.ofNotFound("文件夹不存在", folderIds);
        }
        RepositoryBO repositoryBO = documentEventBus.getRubbishRepository();
        if (repositoryBO == null) {
            return Result.ofErrorStatus("回收站初始化失败");
        }
        //源数据
        FolderBO srcFolder = new FolderBO();
        Long userId = UserContextHolder.getUserId();
        //回收的垃圾文件夹
        LocalDateTime now = LocalDateTime.now();
        BeanUtils.copyProperties(folderBOS.get(0), srcFolder);
        List<DocumentRubbishBO> documentRubbishBOS = new ArrayList<>();
        for (FolderBO folder : folderBOS) {
            //回收的垃圾文件夹
            DocumentRubbishBO documentRubbishBO = DocumentRubbishBO.builder()
                    .createTime(now)
                    .updateTime(now)
                    .tenantId(userId)
                    .rubbishType(DocumentRubbishConstant.GARBAGE_TYPE_FOLDER)   //文件类型
                    .rubbishRepositoryId(repositoryBO.getRepositoryId())    //回收知识库id
                    .sourceRepositoryId(folder.getRepositoryId())//源知识库id
                    .sourceFolderId(folder.getParentFolderId())//源文件id
                    .rubbishId(folder.getFolderId())    //垃圾id
                    .build();
            documentRubbishBOS.add(documentRubbishBO);
        }
        int saveRows = documentRubbishManager.saveAllDocumentRubbish(documentRubbishBOS);
        if (saveRows > 0) {
            //改变文件夹的知识库id和文件夹id
            Set<Long> folderIdList = folderBOS.stream().map(FolderBO::getFolderId).collect(Collectors.toSet());
            FolderBO folderBO = FolderBO.builder().repositoryId(repositoryBO.getRepositoryId()).parentFolderId(0L).folderIds(folderIdList).updateTime(LocalDateTime.now()).build();
            int updateRows = folderManager.updateFolderByIds(folderBO);
            if (updateRows > 0) {
                //当前支持当前页面的文档批量删除，只需调用一次即可
                //调用事件总线重新计算文档大小
                documentEventBus.fireFolderDelHandler(folderBOS.get(0).getFolderId());
                documentEventBus.fireFoldertMoveHandler(srcFolder);
                //删除文件夹的分享
                folderIds.forEach(f -> {
                    documentEventBus.fireFolderStatusHandler(f);
                });
                return Result.success();
            }
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public FolderBO getFolder(Long folderId) {
        return folderManager.getFolder(folderId);
    }

    @Override
    public List<FolderBO> listFolderById(Collection<Long> collection) {
        return folderManager.listFolderById(collection);
    }

    @Override
    public List<FolderBO> listFolder(FolderQuery query) {
        if (query.getParentFolderId() == null) {
            query.setParentFolderId(0L);
        }
        return folderManager.listFolder(query);
    }

    @Override
    public List<Object> listFolderDocument(FolderQuery query) {
        //更新repository访问时间
        LocalDateTime now = LocalDateTime.now();
        RepositoryBO repositoryBO = RepositoryBO.builder().accessTime(now).repositoryId(query.getRepositoryId()).build();
        repositoryManager.updateRepository(repositoryBO);
        if (query.getParentFolderId() != null) {
            //更新folder访问时间
            FolderBO folderBO = FolderBO.builder().accessTime(now).folderId(query.getParentFolderId()).build();
            folderManager.updateFolder(folderBO);
        }
        //定义返回对象
        List<Object> objects = new ArrayList<>();
        if (query.getParentFolderId() == null) {
            query.setParentFolderId(0L);
        }
        List<FolderBO> folderBOS = folderManager.listFolder(query);
        //若文件夹大小为0，则调用统计方法计算大小
        folderBOS.stream()
                .filter(folder -> folder.getFolderSize() <= 0)
                .peek(folder -> documentEventBus.fireFoldertMoveHandler(folder));
        folderBOS = folderBOS.stream()
                .peek(folder -> {
                    folder.setSize(ConvertSizeUtils.readableFileSize(folder.getFolderSize()));
                    folder.setAccessTimeString(CalendarUtils.getDeadlineString(folder.getAccessTime(), LocalDateTime.now()));
                })
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(folderBOS)) {
            userClient.buildByUser(folderBOS,
                    folderBOS.stream().map(e -> e.getCreateUserId()).collect(Collectors.toSet()),
                    FolderBO::getCreateUserId,
                    (folderBO, userDTO) -> folderBO.setCreatedName(userDTO.getUserName()));
        }
        DocumentQuery documentQuery = DocumentQuery.builder()
                .folderId(query.getParentFolderId())
                .repositoryId(query.getRepositoryId())
                .build();
        List<DocumentBO> documentBOList = documentManager.listDocument(documentQuery);
        documentBOList = documentBOList.stream()
                .peek(doc -> {
                    doc.setSize(ConvertSizeUtils.readableFileSize(doc.getFileSize()));
                    doc.setAccessTimeString(CalendarUtils.getDeadlineString(doc.getAccessTime(), LocalDateTime.now()));
                })
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(documentBOList)) {
            userClient.buildByUser(documentBOList,
                    documentBOList.stream().map(e -> e.getCreateUserId()).collect(Collectors.toSet()),
                    DocumentBO::getCreateUserId,
                    (documentBO, userDTO) -> documentBO.setCreatedName(userDTO.getUserName()));
        }

        DocumentFavoriteQuery documentFavoriteQuery = DocumentFavoriteQuery.builder().createUserId(UserContextHolder.getUserId()).build();
        List<DocumentFavoriteBO> documentFavoriteBOS = documentFavoriteManager.listDocumentFavorite(documentFavoriteQuery);
        Map<Long, Long> DocumentFavoriteBOMap = documentFavoriteBOS.stream().collect(Collectors.toMap(DocumentFavoriteBO::getDocumentId, DocumentFavoriteBO::getDocumentFavoriteId));
        Set<Long> documentIds = DocumentFavoriteBOMap.keySet();
        documentBOList.stream().forEach(documentBO -> {
            if (documentIds.contains(documentBO.getDocumentId())) {
                documentBO.setDocumentFavoriteId(DocumentFavoriteBOMap.get(documentBO.getDocumentId()));
            }
        });
        documentBOList.sort(Comparator.comparing(DocumentBO::getDocumentCode));
        if (!CollectionUtils.isEmpty(folderBOS)) {
            objects.addAll(folderBOS);
        }
        if (!CollectionUtils.isEmpty(documentBOList)) {
            objects.addAll(documentBOList);
        }
        return objects;
    }

    @Override
    public int countFolder(FolderQuery query) {
        return folderManager.countFolder(query);
    }

    @Override
    public Result<?> updateMoveFolder(FolderBO folderBO) {
        LocalDateTime now = LocalDateTime.now();
        folderBO.setUpdateTime(now);
        folderBO.setAccessTime(now);
        FolderBO srcFolder = folderManager.getFolder(folderBO.getFolderId());
        //添加文件路径
        RepositoryBO repository = repositoryManager.getRepository(srcFolder.getRepositoryId());
        StringBuffer sb = new StringBuffer(repository.getRepositoryName() + "://");
        getFolderName(folderBO.getParentFolderId(), sb);
        folderBO.setLocation(sb.toString());
        int affectedRows = folderManager.updateFolder(folderBO);
        if (affectedRows > 0) {
            documentEventBus.fireFolderDeletionHandler(folderBO.getFolderId());
            documentEventBus.fireFoldertMoveHandler(srcFolder);
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateNameFolder(FolderBO folderBO) {
        LocalDateTime now = LocalDateTime.now();
        folderBO.setUpdateTime(now);
        folderBO.setAccessTime(now);
        int affectedRows = folderManager.updateFolder(folderBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Transactional
    @Override
    public Result<?> recoverFolder(Long folderId) {
        //通过文档垃圾id查询文档垃圾表
        DocumentRubbishQuery documentRubbishQuery = DocumentRubbishQuery.one().rubbishId(folderId).build();
        List<DocumentRubbishBO> documentRubbishBOS = documentRubbishManager.listDocumentRubbish(documentRubbishQuery);
        //文档垃圾不为空，开始恢复文件
        if (!CollectionUtils.isEmpty(documentRubbishBOS)) {
            DocumentRubbishBO documentRubbishBO = documentRubbishBOS.get(0);
            //查询文件夹信息
            FolderBO folder = folderManager.getFolder(folderId);
            FolderBO srcFolder = new FolderBO();
            BeanUtils.copyProperties(folder, srcFolder);
            //修改文件夹 知识库id
            folder.setRepositoryId(documentRubbishBO.getSourceRepositoryId());
            folder.setParentFolderId(documentRubbishBO.getSourceFolderId());
            int rows = folderManager.updateFolder(folder);
            if (rows > 0) {
                //删除文档垃圾内数据
                rows = documentRubbishManager.deleteDocumentRubbish(documentRubbishBO.getDocumentRubbishId());
                if (rows > 0) {
                    //重新计算恢复后文件大小
                    documentEventBus.fireFolderDeletionHandler(folderId);
                    //此方法只用于文件夹恢复时计算大小
                    documentEventBus.fireFolderRecoverHandler(srcFolder);
                    return Result.success();
                }
            }
        }
        return Result.ofErrorRowsAffected();
    }

    /**
     * 批量恢复
     *
     * @param folderIds
     */
    @Transactional
    @Override
    public Result<?> recoverFolderByIds(Collection<Long> folderIds) {
        //根据文档id查询出垃圾库中的垃圾文件夹信息
        List<DocumentRubbishBO> documentRubbishBOS = documentRubbishManager.listDocumentRubbishByRubbishId(folderIds);
        if (!CollectionUtils.isEmpty(documentRubbishBOS)) {
            List<FolderBO> folderBOS = folderManager.listFolderById(folderIds);
            //将文件夹转换为Map类型，便于查找
            Map<Long, FolderBO> folderBOSMap = folderBOS.stream().collect(Collectors.toMap(FolderBO::getFolderId, folderBO -> folderBO));
            FolderBO srcFolderBO = new FolderBO();
            LocalDateTime now = LocalDateTime.now();
            Set<FolderBO> folders = new HashSet<>();
            //源文档信息
            Map<Long, FolderBO> srcFolders = new HashMap<>();
            documentRubbishBOS.forEach(rubbish -> {
                //源信息
                FolderBO folder = folderBOSMap.get(rubbish.getRubbishId());
                BeanUtils.copyProperties(folder, srcFolderBO);
                //修改文件夹 知识库id
                folder.setRepositoryId(rubbish.getSourceRepositoryId());
                folder.setParentFolderId(rubbish.getSourceFolderId());
                folder.setUpdateTime(now);
                folders.add(folder);
                srcFolders.put(folder.getFolderId(), srcFolderBO);
            });
            int rows = folderManager.updateFolderAll(folders);
            if (rows > 0) {
                //删除文档垃圾内数据
                Set<Long> ids = documentRubbishBOS.stream().map(DocumentRubbishBO::getDocumentRubbishId).collect(Collectors.toSet());
                rows = documentRubbishManager.deleteDocumentRubbishByIds(ids);
                if (rows > 0) {
                    //根据repositoryId分组
                    Map<Long, List<FolderBO>> groupByRepository = folders.stream().collect(Collectors.groupingBy(FolderBO::getRepositoryId));
                    Map<Long, Set<Long>> locationIds = new HashMap<>();
                    //找到每个folder的路径Id
                    folders.forEach(doc -> {
                        Set<Long> docIds = new HashSet<>();
                        getLocationIds(doc.getFolderId(), docIds);
                        locationIds.put(doc.getFolderId(), docIds);
                    });
                    //根据知识库Id分组，获取到某个知识库中需要恢复的最深层的文件Id
                    Map<Long, Set<Long>> locations = new HashMap<>();
                    for (Long repId : groupByRepository.keySet()) {
                        Set<Long> docIds = groupByRepository.get(repId).stream().map(FolderBO::getFolderId).collect(Collectors.toSet());
                        List<Set<Long>> collect = docIds.stream().map(locationIds::get).collect(Collectors.toList());
                        Set<Long> maxSet = getMaxSet(collect);
                        locations.put(repId, maxSet);
                    }
                    //只需计算最深层的文件即可将整个库、文件夹的大小更新
                    for (Long repId : locations.keySet()) {
                        Set<Long> docLocations = locations.get(repId);
                        //获取集合最后一个元素
                        List<Long> fIds = new ArrayList<>(docLocations);
                        Long folderId = fIds.get(fIds.size() - 1);
                        FolderBO srcFolder = srcFolders.get(folderId);
                        documentEventBus.fireFolderDeletionHandler(folderId);
                        documentEventBus.fireFolderRecoverHandler(srcFolder);
                    }
                    /*folders.forEach(folder -> {
                        //重新计算恢复后文件夹大小
                        documentEventBus.fireFolderDeletionHandler(folder.getFolderId());
                        //此方法只用于文件夹恢复时计算大小
                        documentEventBus.fireFolderRecoverHandler(srcFolders.get(folder.getFolderId()));
                    });*/
                    return Result.success();
                }
            }
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> listTreeFolderDocument(FolderQuery toQuery) {
        List<FolderBO> folderBOS = folderManager.listTreeFolderDocument(toQuery);

        List<TreeItem> treeItems = new ArrayList<>();
        if (!CollectionUtils.isEmpty(folderBOS)) {
            treeItems = Tree.buildTreeItem(folderBOS,
                    e -> e.getSource().getFolderId(),
                    e -> e.getSource().getParentFolderId(),
                    e -> e == null || e == 0,
                    e -> e.getFolderId().toString(),
                    e -> e.getFolderName(),
                    //给文件夹设置后缀统一为"folder"
                    e -> GetFileExtensionResponse.builder().fileExtension("folder").build(),
                    (e1, e2) -> {
                        return e1.getValue().getSource().getSequence() - e2.getValue().getSource().getSequence();
                    });
        }
        insertDocument(treeItems, 0L, toQuery.getRepositoryId());
        return Result.success(treeItems);
    }

    @Override
    public Result<?> listTreeFolder(FolderQuery toQuery) {
        List<FolderBO> folderBOS = folderManager.listTreeFolderDocument(toQuery);
        if (CollectionUtils.isEmpty(folderBOS)) {
            return Result.success(new ArrayList<>());
        }
        List<TreeItem> treeItems = Tree.buildTreeItem(folderBOS,
                e -> e.getSource().getFolderId(),
                e -> e.getSource().getParentFolderId(),
                e -> e == null || e == 0,
                e -> e.getFolderId().toString(),
                e -> e.getFolderName(),
                //给文件夹设置后缀统一为"folder"
                e -> GetFileExtensionResponse.builder().fileExtension("folder").build(),
                (e1, e2) -> {
                    return e1.getValue().getSource().getSequence() - e2.getValue().getSource().getSequence();
                });
        return Result.success(treeItems);
    }

    /**
     * 获取文件夹信息
     * @param folderId
     * @return
     */
    @Override
    public GetFolderResponse getFolderInfoById(Long folderId) {
        FolderBO folder = folderManager.getFolder(folderId);
        GetFolderResponse folderResponse = FolderConverter.toResponse(folder);
        Set<DocumentBO> set = new HashSet<>();
        getdocumentIds(folderId, set);
        //设置文档数量
        folderResponse.setDocumentCount((long) set.size());
        folderResponse.setSize(ConvertSizeUtils.readableFileSize(folderResponse.getFolderSize()));
        Set<FolderBO> folderSet = new HashSet<>();
        getFolder(folderId, folderSet);
        //设置文件夹数量
        folderResponse.setFolderCount((long) folderSet.size());
        return folderResponse;
    }

    @Override
    public Result<List<GetFolderResponse>> getRelease(FolderQuery query) {
        RepositoryBO releaseRepository = repositoryManager.getReleaseRepository();
        query.setRepositoryId(releaseRepository.getRepositoryId());

        //更新repository访问时间
        LocalDateTime now = LocalDateTime.now();
        RepositoryBO repositoryBO = RepositoryBO.builder().accessTime(now).repositoryId(releaseRepository.getRepositoryId()).build();
        repositoryManager.updateRepository(repositoryBO);

        /*if (query.getParentFolderId() != null) {
            //更新folder访问时间
            FolderBO folderBO = FolderBO.builder().accessTime(now).folderId(query.getParentFolderId()).build();
            folderManager.updateFolder(folderBO);
        }

        //定义返回对象
        List<Object> objects = new ArrayList<>();
        if (query.getParentFolderId() == null) {
            query.setParentFolderId(0L);
        }
        List<FolderBO> folderBOS = folderManager.listFolder(query);

        //若文件夹大小为0，则调用统计方法计算大小
        folderBOS.stream()
                .filter(folder -> folder.getFolderSize() <= 0)
                .peek(folder -> documentEventBus.fireFoldertMoveHandler(folder));
        folderBOS = folderBOS.stream()
                .peek(folder -> {
                    folder.setSize(ConvertSizeUtils.readableFileSize(folder.getFolderSize()));
                    folder.setAccessTimeString(CalendarUtils.getDeadlineString(folder.getAccessTime(), LocalDateTime.now()));
                })
                .collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(folderBOS)) {
            userClient.buildByUser(folderBOS,
                    folderBOS.stream().map(e -> e.getCreateUserId()).collect(Collectors.toSet()),
                    FolderBO::getCreateUserId,
                    (folderBO, userDTO) -> folderBO.setCreatedName(userDTO.getUserName()));
        }

        if (!CollectionUtils.isEmpty(folderBOS)) {
            return Result.success(FolderConverter.toResponse(folderBOS));
        }*/
        return Result.success();
    }

    /**
     * 复制文件夹
     * @param folderBO
     * @return
     */
    @Transactional
    @Override
    //TODO 待优化
    public Result<?> copyFolder(FolderBO folderBO) {
        if (folderBO == null) {
            return Result.fail("空参数");
        }
        //源folder对象信息
        FolderBO srcFolder = folderManager.getFolder(folderBO.getFolderId());
        FolderBO newFolder = buildFolder(srcFolder, folderBO);
        FolderBO folder = folderManager.saveFolder(newFolder);
        build(srcFolder, folder);
        return Result.success();
    }

    @Override
    public Result<GetFolderResponse> createManufacture(CreateManufactureFolderRequest request) {
        //获取第一层级 子项文件夹
        FolderBO productDictCodeFolder = folderManager.getFolderByNameAndRepository(ListFolderRequest.builder()
                .pageIndex(0)
                .pageSize(1)
                .repositoryId(request.getRepositoryId())
                .parentFolderId(0L)
                .folderName(request.getSubProductDictCodeFolderName()).build());
        if (Objects.isNull(productDictCodeFolder)) {//如果不存在直接创建
            FolderBO folderBO = FolderBO.builder()
                    .repositoryId(request.getRepositoryId())
                    .folderName(request.getSubProductDictCodeFolderName())
                    .parentFolderId(0L).build();
            buildFolderBo(folderBO);
            productDictCodeFolder = folderManager.saveFolder(folderBO);
            if (Objects.isNull(productDictCodeFolder)) {//创建不成功返回错误
                return Result.ofErrorRowsAffected();
            }
        }
        return Result.success(FolderConverter.toResponse(productDictCodeFolder));

    }

    private void build(FolderBO folderBO, FolderBO paramFolder) {
        List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.builder().folderId(folderBO.getFolderId()).build());
        if (!documentBOS.isEmpty()) {
            documentBOS.forEach(doc -> documentClient.copyDocument(CopyDocumentRequest.builder().documentId(doc.getDocumentId()).destFolderId(paramFolder.getFolderId()).destRepositoryId(paramFolder.getRepositoryId()).build()));
        }
        List<FolderBO> folderBOS = folderManager.listFolder(FolderQuery.builder().parentFolderId(folderBO.getFolderId()).build());
        if (folderBOS.isEmpty()) {
            return;
        }
        folderBOS.forEach(f -> {
            FolderBO newFolder = buildFolders(f, folderBO);
            FolderBO folder = folderManager.saveFolder(newFolder);
            build(f, folder);
        });
    }

    public List<TreeItem> insertDocument(List<TreeItem> items, Long parentFolderId, Long repositoryId) {
        //定义文档树状集合
        List<TreeItem> tritems = new ArrayList<>();
        //遍历文档集合
        DocumentQuery query = DocumentQuery.builder().repositoryId(repositoryId).folderId(parentFolderId).build();
        List<DocumentBO> documentBOS = documentManager.listDocument(query);
        for (DocumentBO documentBO : documentBOS) {
            GetFileExtensionResponse getFileExtensionResponse = FileExtensionConverter.toResponse(documentBO);
            TreeItem treeItem = new TreeItem();
            treeItem.setValue(documentBO.getDocumentId().toString());
            treeItem.setLabel(documentBO.getDocumentName() + documentBO.getFileExtension());
            treeItem.setMove(true);
            treeItem.setTag(getFileExtensionResponse);
            tritems.add(treeItem);
        }
        if (items != null) {
            //获取下一级集合
            for (int i = 0; i < items.size(); i++) {
                TreeItem item = items.get(i);
                item.setChildren(insertDocument(item.getChildren(), Long.parseLong(item.getValue()), repositoryId));
            }
            items.addAll(tritems);
        } else {
            items = tritems;
        }
        return items;
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        addDocumentChangeHandle();
        addDocumentMoveHandle();
        addFolderChangeHandle();
        addFolderMoveHandle();
        addFolderDeleteHandle();
        addFolderRecoverHandle();
    }

    private void setFolderSize(Long folderId) {
        if (!Objects.isNull(folderId) && folderId != 0) {
            Long totalSize = 0L;
            List<FolderBO> folderBOS = folderManager.listFolder(FolderQuery.max()
                    .parentFolderId(folderId).build());
            for (FolderBO folderBO : folderBOS) {
                totalSize += folderBO.getFolderSize();
            }
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .folderId(folderId).build());
            for (DocumentBO documentBO : documentBOS) {
                totalSize += documentBO.getFileSize();
            }
            folderManager.updateFolder(FolderBO.builder().folderId(folderId).folderSize(totalSize).build());
        } else {
            return;
        }
        FolderBO folder = folderManager.getFolder(folderId);
        Long parentFolderId = folder.getParentFolderId();
        setFolderSize(parentFolderId);
    }

    private void addFolderChangeHandle() {
        documentEventBus.addFolderDeletionHandler((folderId) -> {
            FolderBO folder = folderManager.getFolder(folderId);
            if (folder == null) {
                return;
            }
            setFolderSize(folder.getParentFolderId());
            Long folderRepositoryId = folder.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(folderRepositoryId).build());
            Long repoSize = 0L;
            for (DocumentBO documentBO : documentBOS) {
                repoSize += documentBO.getFileSize();
            }
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(folderRepositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    private void addFolderDeleteHandle() {
        documentEventBus.addFolderDelHandler((folderId) -> {
            FolderBO folder = folderManager.getFolder(folderId);
            if (folder == null) {
                return;
            }
            setFolderSize(folder.getParentFolderId());
            Long folderRepositoryId = folder.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(folderRepositoryId).build());
            Long repoSize = 0L;
            Set<DocumentBO> set = new HashSet<>();
            getdocumentIds(folderId, set);
            Long fileSize = set.stream().mapToLong(DocumentBO::getFileSize).sum();
            for (DocumentBO documentBO : documentBOS) {
                repoSize += documentBO.getFileSize();
            }
            repoSize += fileSize;
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(folderRepositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    private void addFolderMoveHandle() {
        documentEventBus.addFolderMoveHandler((folderBo) -> {
            if (folderBo == null) {
                return;
            }
            setFolderSize(folderBo.getParentFolderId());
            Long folderRepositoryId = folderBo.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(folderRepositoryId).build());
            Long repoSize = 0L;
            Set<DocumentBO> set = new HashSet<>();
            getdocumentIds(folderBo.getFolderId(), set);
            for (DocumentBO documentBO : documentBOS) {
                if (set.contains(documentBO)) {
                    continue;
                }
                repoSize += documentBO.getFileSize();
            }
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(folderRepositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    private void addFolderRecoverHandle() {
        documentEventBus.addFolderRecoverHandle((folderBo) -> {
            if (folderBo == null) {
                return;
            }
            setFolderSize(folderBo.getParentFolderId());
            Long folderRepositoryId = folderBo.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(folderRepositoryId).build());
            Long repoSize = 0L;
            Set<DocumentBO> set = new HashSet<>();
            getdocumentIds(folderBo.getFolderId(), set);
            Long fileSize = set.stream().mapToLong(DocumentBO::getFileSize).sum();
            for (DocumentBO documentBO : documentBOS) {
                repoSize += documentBO.getFileSize();
            }
            repoSize -= fileSize;
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(folderRepositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    private void addDocumentChangeHandle() {
        documentEventBus.addDocumentEditHandler((documentId) -> {
            DocumentBO document = documentManager.getDocument(documentId);
            if (document == null) {
                return;
            }
            Long folderId = document.getFolderId();
            setFolderSize(folderId);

            Long repositoryId = document.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(repositoryId).build());
            Long repoSize = 0L;
            for (DocumentBO documentBO : documentBOS) {
                repoSize += documentBO.getFileSize();
            }
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(repositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    private void addDocumentMoveHandle() {
        documentEventBus.addDocumentMoveHandler((documentBo) -> {
            if (documentBo == null) {
                return;
            }
            setFolderSize(documentBo.getFolderId());
            Long repositoryId = documentBo.getRepositoryId();
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .repositoryId(repositoryId).build());
            Long repoSize = 0L;
            for (DocumentBO documentBO : documentBOS) {
                repoSize += documentBO.getFileSize();
            }
            repositoryManager.updateRepository(RepositoryBO.builder().repositoryId(repositoryId)
                    .repositorySize(repoSize).build());
        });
    }

    /**
     * @author Greekn Zhang
     * @date 2021/4/30 11:56
     * @param folderId
     * @param documentIds
     * @return java.util.Set<com.xy.biz.fd.domain.bo.DocumentBO>
     * @description 获取文件夹下的所有文档
     */
    private Set<DocumentBO> getdocumentIds(Long folderId, Set<DocumentBO> documentIds) {
        if (!Objects.isNull(folderId) && folderId != 0) {
            List<DocumentBO> documentBOS = documentManager.listDocument(DocumentQuery.max()
                    .folderId(folderId).build());
            documentIds.addAll(documentBOS);
            List<FolderBO> folderBOS = folderManager.listFolder(FolderQuery.max()
                    .parentFolderId(folderId).build());
            for (FolderBO folderBO : folderBOS) {
                return getdocumentIds(folderBO.getFolderId(), documentIds);
            }
        }
        return null;
    }


    /**
     * @author Greekn Zhang
     * @date 2021/4/29 14:05
     * @param folderId
     * @param sb
     * @return java.lang.StringBuffer
     * @description 递归获取文件夹名字
     */
    private StringBuffer getFolderName(Long folderId, StringBuffer sb) {
        if (!Objects.isNull(folderId) && folderId != 0) {
            FolderBO folder = folderManager.getFolder(folderId);
            getFolderName(folder.getParentFolderId(), sb);
            return sb.append(folder.getFolderName()).append("/");
        } else {
            return null;
        }
    }

    /**
     * @author Greekn Zhang
     * @date 2021/4/30 10:31
     * @param folderId
     * @param folder
     * @description 递归获取改文件夹id下所有文件夹
     */
    private void getFolder(Long folderId, Set<FolderBO> folder) {
        List<FolderBO> folderBOS = folderManager.listFolder(FolderQuery.max().parentFolderId(folderId).build());
        if (folderBOS != null && !CollectionUtils.isEmpty(folderBOS)) {
            folder.addAll(folderBOS);
        } else {
            return;
        }
        for (FolderBO folderBO : folderBOS) {
            getFolder(folderBO.getFolderId(), folder);
        }
    }


    /**
     * @author Greekn Zhang
     * @date 2021/4/30 11:55
     * @param folderId
     * @param ids
     * @description 递归获取文件夹路径的id
     */
    private void getLocationIds(Long folderId, Set<Long> ids) {
        FolderBO folder = folderManager.getFolder(folderId);
        if (folder != null) {
            ids.add(folder.getFolderId());
            getLocationIds(folder.getParentFolderId(), ids);
        } else {
            return;
        }
    }

    /**
     * @author Greekn Zhang
     * @date 2021/4/30 15:08
     * @param list
     * @return java.util.Set<java.lang.Long>
     * @description 获取最大set集合
     */
    private Set<Long> getMaxSet(List<Set<Long>> list) {
        Set<Long> set = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            if (list.get(i).size() >= set.size()) {
                set = new HashSet<>(list.get(i));
            }
        }
        return set;
    }

    private FolderBO buildFolder(FolderBO srcFolder, FolderBO paramFolder) {
        FolderBO targetFolder = new FolderBO();
        targetFolder.setParentFolderId(paramFolder.getParentFolderId());
        if (paramFolder.getParentFolderId() == null) {
            targetFolder.setParentFolderId(0L);
        }
        //添加文件路径
        RepositoryBO repository = repositoryManager.getRepository(paramFolder.getRepositoryId());
        StringBuffer sb = new StringBuffer(repository.getRepositoryName() + "://");
        getFolderName(targetFolder.getParentFolderId(), sb);
        targetFolder.setLocation(sb.toString());
        targetFolder.setFolderName(
                srcFolder.getParentFolderId().equals(paramFolder.getParentFolderId()) ?
                        changeFolderName(srcFolder.getFolderName()) : srcFolder.getFolderName());
        targetFolder.setTenantId(UserContextHolder.getTenantId());
        targetFolder.setRepositoryId(paramFolder.getRepositoryId());
        targetFolder.setPermission(repository.getPermission());
        targetFolder.setFolderSize(srcFolder.getFolderSize());
        targetFolder.setCreateUserId(UserContextHolder.getUserId());
        LocalDateTime now = LocalDateTime.now();
        targetFolder.setAccessTime(now);
        targetFolder.setCreateTime(now);
        targetFolder.setUpdateTime(now);
        targetFolder.setDeleteFlag(Boolean.FALSE);
        return targetFolder;
    }

    /**
     * @author Greekn Zhang
     * @date 2021/5/11 16:35
     * @return java.lang.String
     * @description 复制文件夹时若相同文件夹下有相同名文件夹则会进行改名
     */
    private String changeFolderName(String folderName) {
        StringBuffer stringBuffer = new StringBuffer(folderName);
        if (folderName.contains(" - 副本")) {
            String substring = folderName.substring(folderName.lastIndexOf("本") + 1);
            if (!("").equals(substring) && StringUtils.isNumeric(substring)) {
                Long num = Long.parseLong(substring);
                return stringBuffer.deleteCharAt(stringBuffer.length() - 1).append(++num).toString();
            }
            return stringBuffer.append(2).toString();
        }
        return stringBuffer.append(" - 副本").toString();
    }

    private FolderBO buildFolders(FolderBO srcFolder, FolderBO paramFolder) {
        FolderBO targetFolder = new FolderBO();
        targetFolder.setParentFolderId(paramFolder.getFolderId());
        if (paramFolder.getFolderId() == null) {
            targetFolder.setParentFolderId(0L);
        }
        //添加文件路径
        RepositoryBO repository = repositoryManager.getRepository(paramFolder.getRepositoryId());
        StringBuffer sb = new StringBuffer(repository.getRepositoryName() + "://");
        getFolderName(targetFolder.getParentFolderId(), sb);
        targetFolder.setLocation(sb.toString());
        targetFolder.setFolderName(
                srcFolder.getParentFolderId().equals(paramFolder.getFolderId()) ?
                        srcFolder.getFolderName() + " - 副本" : srcFolder.getFolderName());
        targetFolder.setTenantId(UserContextHolder.getTenantId());
        targetFolder.setRepositoryId(paramFolder.getRepositoryId());
        targetFolder.setPermission(repository.getPermission());
        targetFolder.setFolderSize(srcFolder.getFolderSize());
        targetFolder.setCreateUserId(UserContextHolder.getUserId());
        LocalDateTime now = LocalDateTime.now();
        targetFolder.setAccessTime(now);
        targetFolder.setCreateTime(now);
        targetFolder.setUpdateTime(now);
        targetFolder.setDeleteFlag(Boolean.FALSE);
        return targetFolder;
    }
}
